/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.swing.tabcontrol.plaf;

import org.netbeans.swing.tabcontrol.TabData;
import org.netbeans.swing.tabcontrol.TabDisplayer;

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Table model that provides a sorted, multi-column list of tabs
 *
 * @author Tim Boudreau
 */
class TabListPopupTableModel implements TableModel {
    private transient TabDisplayer displayer = null;
    private transient ArrayList tableModelListenerList;
    /**
     * Used to estimate number of cells fitting to given space.
     */
    private int rowHeight;
    /**
     * Sorted tabs
     */
    private List tabs = new ArrayList();

    /**
     * Creates a new instance of TabTreeModel
     */
    public TabListPopupTableModel() {
    }

    public TabListPopupTableModel(TabDisplayer displayer) {
        attach(displayer);
        if (tableModelListenerList != null) {
            if (event == null) {
                event = new TableModelEvent(this);
            }
            fireTableChanged(event);
        }
    }

    public void setRowHeight(int rowHeight) {
        this.rowHeight = rowHeight;
    }

    public void attach(TabDisplayer c) {
        if (displayer != null) {
            detach();
        }
        this.displayer = c;
        int count = displayer.getModel().size();
        int colCount = calcColumns(count);
        int rowCount = count / colCount;
        //avoid div by 0
        if (count > 0) {
            if (count % rowCount > 0)
                rowCount++;
            setRowsAndColumns(rowCount, colCount);
        } else {
            setRowsAndColumns(0, 0);
        }
        //Duplicate data model and sort it by text (TopComponent name)
        tabs.clear();
        tabs.addAll(displayer.getModel().getTabs());
        Collections.sort(tabs);
    }

    /**
     * Try to estimate available space in displayer for table according to height of
     * table cell.
     */
    private int calcColumns(int count) {
        //Number of row which fits into displayer
        int nRow = displayer.getHeight() / rowHeight;
        //Add some heuristic here: If number of row is below
        //some value (simply it does not fit into displayer) set some fixed value.
        if (nRow <= 2) {
            nRow = 10;
        }

        int result = (count / nRow) + 1;
        //Old code
        //FYI, the code below reduces wasted space by using multiples of 2 or
        //3 columns depending on which the number of items we have to display
        //divides into with a smaller remainder.  Not sure why it was commented
        //out. -Tim
        /*int result = 1;
        if (count > 10) {
            int by2 = count % 2;
            int by3 = count % 3;
            if (by2 == 0) {
                result = 2;
            } else if (by3 == 0) {
                result = 3;
            } else if (by2 > by3) {
                result = 4;
            } else {
                result = 3;
            }
        }*/
        
        return result;
    }

    public void detach() {
        displayer = null;
        tabs.clear();
    }

    public Class getColumnClass(int columnIndex) {
        return Integer.class;
    }

    public String getColumnName(int columnIndex) {
        return "";
    }

    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }

    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        //Do nothing
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
        if ((rowIndex == -1) || (columnIndex == -1)) {
            return new Integer(-1);
        } else {
            int mdlIdx = (columnIndex * getRowCount()) + rowIndex;
            if (mdlIdx < tabs.size()) {
                return tabs.get(mdlIdx);
            } else {
                return null;
            }
        }
    }

    public synchronized void addTableModelListener(
            javax.swing.event.TableModelListener listener) {
        if (tableModelListenerList == null) {
            tableModelListenerList = new ArrayList();
        }
        tableModelListenerList.add(listener);
    }

    public synchronized void removeTableModelListener(
            javax.swing.event.TableModelListener listener) {
        if (tableModelListenerList != null) {
            tableModelListenerList.remove(listener);
        }
    }

    private void fireTableChanged(javax.swing.event.TableModelEvent event) {
        java.util.ArrayList list;
        synchronized (this) {
            if (tableModelListenerList == null)
                return;
            list = (ArrayList) tableModelListenerList.clone();
        }
        for (int i = 0; i < list.size(); i++) {
            ((javax.swing.event.TableModelListener) list.get(i)).tableChanged(
                    event);
        }
    }

    private TableModelEvent event = null;
    private int rows;
    private int cols;

    public void setRowsAndColumns(int rows, int cols) {
        if ((this.rows != rows) || (this.cols != cols)) {
            this.rows = rows;
            this.cols = cols;
            if (event == null) {
                event = new TableModelEvent(this);
            }
            fireTableChanged(event);
        }
    }

    public int getRowCount() {
        return rows;
    }

    public int getColumnCount() {
        return cols;
    }

}
